package 逆变点与协变点

/**
  * @author juntao zhang
  */
object Test extends App {

  class Person {
    def hi(): Unit = {
      println("hi person")
    }

    override def toString: String = "Person\n"
  }

  class Student extends Person {
    def hello(): Unit = {
      println("hello")
    }

    override def hi(): Unit = {
      println("hi student")
    }

    override def toString: String = "Student\n"
  }

  // Person> Student
  //===================================协变点 返回值===================================

  //Function1[Student, Person] > Function1[Student, Student]
  val fun = new Function1[Student, Student] {
    def apply(x: Student): Student = {
      //return 发生协变, 实际return 更具体
      x
    }
  }

  def test(fun: Function1[Student, Person], stu: Student) {
    print(fun.apply(stu)) //Student
  }
  test(fun, new Student)

//  def test2(fun: Student => Person, stu: Student) {
//    print(fun(stu))
//  }
//  test2(x => x, new Student)

  //===================================逆变点  参数===================================
  //Function1[Student, Person] > Function1[Person, Person]
  val fun1 = new Function1[Person, Person] {
    def apply(x: Person): Person = { //x 发生逆变, 实际传入只会更具体
      x
    }
  }

  def test1(fun: Function1[Student, Person], stu: Student) {
    print(fun.apply(stu)) //Student
  }

  //  def test1(fun: Student => Person, stu: Student) {
  //    print(fun(stu))
  //  }

  //  test1(fun1, new Student)

  trait Fun[+T1, -T2, +R] {
    def apply(fun: Function1[T1, T2], param: T2): R
  }

  val f = new Fun[Person, Student, Student] {
    //  协变点确定
    //(         -         )  =>  (+) default
    //(      -        , - )  =>  (+)
    //(-( (-) => (+) ), - )  =>  (+)
    //(   (+) => (-)  , - )  =>  (+)
    override def apply(fun: Person => Student, stu: Student): Student = {
      println("fun1")
      fun(stu)
    }
  }

  println("fun return => " + f((stu: Person) => {
    println("fun2")
    stu.hi()
    stu.asInstanceOf[Student]
  }, new Student))

}
